package com.wyl.idempotentcheck.common;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.wyl.idempotentcheck.annotation.Idempotent;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;


@Aspect
@Component
@Slf4j
public class IdempotentAspect {
    private Logger logger = LoggerFactory.getLogger(IdempotentAspect.class);

    @Autowired
    private RedisService redisService;

    @Around("@annotation(idempotent)")
    public Object aroundMethod(ProceedingJoinPoint pjp, Idempotent idempotent)throws Throwable{
        Object[] args = pjp.getArgs();

        long timeOut = idempotent.value();

        String encode = getMd5Value(args);

        try{
            boolean checkFormRedis = redisService.checkForm(encode,timeOut);
            if (checkFormRedis) {
                throw new CommonException(Code.RepeatSubmit,Code.RepeatSubmit.getMsg());
            }
            //继续执行业务代码
            return pjp.proceed();
        } catch (CommonException e) {
            logger.error("操作失败：" + e.getMessage(), e);
            if (Code.RepeatSubmit.getCode() != e.getCode()) {
                //若存在其他的CommonException自定义异常（如服务内部错误），需要删除校验的key，支持重复提交
                redisService.delete(encode);
            }
            throw e;
        } catch (Exception e){
            logger.error("幂等性校验出错：" + e.getMessage(), e);
            throw e;
        }

    }

    /**
     * 对传入的参数进行MD5加密
     * @param args
     * @return
     */
    private String getMd5Value(Object[] args) {
        String md5 = "null";
        if (args.length == 0) {
            return md5;
        } else {
            StringBuilder jsonString = new StringBuilder(JSON.toJSONString(args));
            md5 = SecureUtil.md5(jsonString.toString());
        }
        return md5;
    }

}
